package com.dmatek.uwb.packet.ianalysis;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Map;

import com.dmatek.uwb.packet.ianalysis.callback.IReportCallBack;
import com.dmatek.uwb.packet.ianalysis.handler.AnalysisPackHandlers;
import com.dmatek.uwb.util.tool.CommonUtils;
import com.dmatek.uwb.xml.dom.bean.BaseNode;
/**   
 * Uwb数据监听的启动类
 * @Description: TODO
 * @author zhangfu  
 * @date 2019年12月3日 上午11:29:20 
 * @version V1.0
 */
public class UwbMonitorBootStrap extends BaseMonitorBootStrap implements IReportCallBack<ChannelHandlerContext>{
	// 处理数据包的Group
	private EventLoopGroup workerGroup;
	// 启动器
	private Bootstrap bootStrap;
	// 绑定的本地地址
	private SocketAddress localAddress;
	private ChannelFuture channelFuture;
	// 线程运行的标志, 设置为volatile保证线程拷贝的副本变量值更新以后马上反馈到主存变量上
	private volatile boolean isRunning;
	// Nio通道锁
	private final Object channelLock = new Object();
	// 用于向底层基站发送数据的Channel处理的上下文对象
	private volatile ChannelHandlerContext localChannelHandlerContext;
	@SafeVarargs
 	public UwbMonitorBootStrap(IAnalysisLocatorPack... iAnalysisLocatorPacks) {
		super(iAnalysisLocatorPacks);
	}
	/***
	 * 初始化相关参数
	 */
	@Override
	public void init(String ip, int port, Map<String, BaseNode> enodesMap)
			throws Exception {
		// 初始化消息接收的Group
		workerGroup = new NioEventLoopGroup();
		// 创建引导类
		bootStrap = new Bootstrap();
		// 创建本地网络地址
		localAddress = new InetSocketAddress(ip, port);
	}
	/**
	 * 启动网络监听
	 */
	@Override
	public synchronized void start() throws Exception {
		if (null == localAddress) { // 说明没有进行初始化
			throw new Exception("you didn't initialize it.");
		}
		/**
		 * 获取解析数据包的对象数组, 当然这个对象数组不能为空, 因为为空的话将无意义
		 */
		IAnalysisLocatorPack[] iAnalysisLocatorPacks = getiAnalysisLocatorPacks();
		if (CommonUtils.isEmpty(iAnalysisLocatorPacks)) {
			throw new Exception("The packet handler cannot be null.");
		}
		// bootStrap 绑定工作组, 定义channel实例类型及handler
		bootStrap.group(workerGroup).channel(NioDatagramChannel.class)
				.handler(new AnalysisPackHandlers(this, iAnalysisLocatorPacks));
		// 绑定监听地址
		channelFuture = bootStrap.bind(localAddress).sync();
		isRunning = true;
	}
	/***
	 * 停止网络监听
	 */
	@Override
	public synchronized void stop() throws Exception {
		if(!isRunning) {
			// 当前不是处在运行状态不能进行关闭
			throw new Exception("Sorry, the task is not running and cannot be closed.");
		}
		if(null != channelFuture) {
			// 关闭通道
			channelFuture.channel().close();
			channelFuture = null;
		}
		if(null != workerGroup) {
			// 将工作组优雅关闭
			workerGroup.shutdownGracefully();
			workerGroup = null;
		}
		// 将相关对象置为空, 让垃圾回收器回收相关的对象
		localAddress = null;
		bootStrap = null;
		isRunning = false;
	}
	/***
	 * 返回监听的执行状态
	 */
	@Override
	public boolean isRunning() throws Exception {
		return isRunning;
	}
	/***
	 * 这个回传函数是在启动网络监听时回传过来的 启动网络监听后, 
	 * Channel被激活并调用channelActive函数, 在这个函数中调用回调函数,
	 * 这里也可以采用 channelFuture 中的Channel或其它方式返回发送的对象.
	 * 
	 */
	@Override
	public void callBack(ChannelHandlerContext ct) throws Exception {
		synchronized (channelLock) {
			this.localChannelHandlerContext = ct;
		}
	}
	/***
	 * 通过回传过来的Channel对象发送数据包
	 */
	@Override
	public void sendData(Object obj) throws Exception {
		if (null != localChannelHandlerContext) {
			synchronized (channelLock) {
				// 内部再加一个判断这样是为了防止判断非空以后, 其它线程把这个对象再次置为空, 所以在内部再加一个判断.
				if(null != localChannelHandlerContext) {
					// 将Udb的数据包DatagramPacket向网络中发出
					localChannelHandlerContext.writeAndFlush(obj);
				}
			}
		}
	}
}
